from IPython.display import display
from IPython.display import HTML
import IPython.core.display as di # Example: di.display_html('<h3>%s:</h3>' % str, raw=True)
# This line will hide code by default when the notebook is exported as HTML
di.display_html('<script>jQuery(function() {if (jQuery("body.notebook_app").length == 0) { jQuery(".input_area").toggle(); jQuery(".prompt").toggle();}});</script>', raw=True)
# This line will add a button to toggle visibility of code blocks, for use with the HTML export version
di.display_html('''<button onclick="jQuery('.input_area').toggle(); jQuery('.prompt').toggle();">Toggle code</button>''', raw=True)
%qtconsole
#2019/03/28 C1S04_WFS_stress_compensation_90mm from C1S04_WFS_stress_compensation_90mm,
# made together, to verify old results. Eventually used also for the 70 mm version.
# note that stress_compensation functions were completely changed before this notebook.
# rms_roi column was changed to fom_roi, and all functions were adapted to work on a generic
# fom that accept data,x,y. The change of label breaks compatibility, so all previous
# notebooks will not work.
# Also this notebook, crop nans from data and align corners.
# The notebook was tested with old values, showing that the alignment of corners (and
# the changes in optimization code) are irrelevant. Results are not visualized here
# but are saved in 'VK_reproduce'. All changes are due to the new crop,
# numbers are still not far from previous, just a bit smaller.
#2019/03/27 PCO1S24_PZT_stress_compensation from C1S04_PZT_stress_compensation
# Here stress needed to calculate compensating stress for ideal shape of 0.5 um axial sag is calculated.
# Calculation is made on actual shape after PZT deposition.
# Part was gold coated at PSU.
%reset
#pylab qt -> open windows, needs display
%pylab qt
%load_ext autoreload
%autoreload 2
#from pySurf.fit_cylinder import *
#from pySurf.points import *
from pySurf.points import plot_points,matrix_to_points2
from pySurf.points import subtract_points,level_points
from pySurf.points import points_find_hull,crop_points
from pySurf.psd2d import calculatePSD
from pySurf.points import points_autoresample
#from calibrate_align import *
from pyProfile.profile import polyfit_profile
from plotting.multiplots import compare_images
from dataIO.fn_add_subfix import fn_add_subfix
from dataIO.span import span
#from PSDanalysis import *
from pySurf.instrumentReader import matrix4D_reader
import os
from pySurf.instrumentReader import bin_reader
from plotting.add_clickable_markers import add_clickable_markers2
from plotting.backends import maximize
from pySurf.instrumentReader import points_reader
from pySurf.affine2D import plot_transform,find_rototrans,find_affine
from pySurf.distanceTable import distanceTable
from pySurf.data2D_class import Data2D
from pySurf.data2D import data_from_txt
from dataIO.outliers import remove_outliers
import pandas as pd
pwd
from pySurf.psd2d import calculatePSD
from utilities.imaging import fitting as fit
from scripts.stress_compensation import comp2, scale_fit2, trioptimize, fom_rms as fom, fom_sl
from pySurf.instrumentReader import fitsWFS_reader
correct_misalignment=fit.fitConeMisalign
Aligned and registered sample figure are loaded from PZT stress fit analysis.
outfolder=r'results\C1S04_WFS_stress_compensation_90mm' #set output
allres=pd.DataFrame() #will contain all results
wf=r'results\C1S04_PZT_stress_fit\wfs_substrate_aligned.dat'
p2=Data2D(file=wf,reader=data_from_txt,delimiter=' ',units=['mm','mm','$\mu$m'],
name='C1S04 PZT WFS data',addaxis=1,center=(0,0))
plt.clf()
p2.plot()
display(plt.gcf())
p2.save(os.path.join(outfolder,fn_add_subfix(wf,'','.dat',strip=True)))
plt.savefig(os.path.join(outfolder,fn_add_subfix(wf,'','.png',strip=True)))
from pySurf.data2D import add_clickable_markers2
ax=add_clickable_markers2()
print(ax.markers)
m1=[[-50.91535317274073, 49.808209478596886],
[-53.07634713026975, -47.97676709959098],
[49.84099009704956, -49.32738832304663],
[52.54223254396083, 47.647215521067885]]
m2=[[-50.8,50.8],[-50.8,-50.8],[50.8,-50.8],[50.8,50.8]]
trans=find_affine(m1,m2)
plt.figure(1)
plt.clf()
p1=p2.apply_transform(trans)
p1=p1.crop([-50.8,50.8],[-50.8,50.8])
p1.level().plot()
display(plt.gcf())
#test, This reproduces exactly the previous case of 90 mm optimization, showing that
# alignment has no relevance, but crop does.
#plt.figure(1)
#plt.clf()
#p1=p2
##p1=p1.crop([-50.8,50.8],[-50.8,50.8])
#p1.level().plot()
#display(plt.gcf())
from pySurf.testSurfaces import make_sag
s1=Data2D(make_sag(*(p1.data.shape[::-1]))[0]*0.5,p1.x,p1.y,name='Target Shape',units=p1.units)
Figures below show the initial and target shape and the initial deviation that needs to be corrected in form of opposite stress, as surface and as central axial profiles.
#calculate deviation from ideal shape
plt.figure()
maximize()
ax1=plt.subplot(131)
p1.level((1,1)).plot()
ax2=plt.subplot(132,sharex=ax1,sharey=ax1)
s1.level((1,1)).plot()
ax3=plt.subplot(133,sharex=ax1,sharey=ax1)
sdiff=(p1-s1).level((1,1))
sdiff.name='Initial deviation from target shape'
sdiff.plot()
plt.clim([-1,1])
display(plt.gcf())
p1.save(os.path.join(outfolder,'wfs_PZT_aligned.dat'))
s1.save(os.path.join(outfolder,'target_shape.dat'))
sdiff.save(os.path.join(outfolder,'figure_change_aligned.dat'))
plt.savefig(os.path.join(outfolder,'initial_deviation.png'))
from pyProfile.profile import level_profile, subtract_profiles
from pySurf.points import extract_profile
## Extract axial profile
x1,y1 = level_profile(*(extract_profile(p1.topoints(),(0,-45),(0,45))))
x2,y2 = level_profile(*(extract_profile(s1.topoints(),(0,-45),(0,45))))
xd,yd = level_profile(*subtract_profiles(x2,y2,x1,y1))
plt.figure()
plt.plot(x1,y1,label='PZT WFS Data')
plt.plot(x2,y2,label='Target Shape')
plt.plot(xd,yd,label='Optimal Compensation')
plt.xlabel(p1.units[0])
plt.ylabel(p1.units[2])
plt.grid(1)
plt.ylim([-0.8,0.8])
plt.legend(loc=0)
plt.title('central axial profiles')
display(plt.gcf())
plt.savefig(os.path.join(outfolder,'data_central_profile.png'))
prfolder='fit_VK'
os.makedirs(os.path.join(outfolder,prfolder),exist_ok=True)
Compensating stress is calculated starting from Vladimir Kradinov's simulation 2018/06/19 corresponding to a coating with uniform integrated stress 300 MPa um.
The stress matching deviation of surface from target value is determined by finding the best fit scale coefficient $s$ that minimizes the rms of surface difference:
$S_\textrm{WFS} - s S_{target}$
This calculation is shown below alone and in comparison with data. A stress opposite in sign will bring the sample surface to a shape that is close to target value.
from pySurf.instrumentReader import points_reader, fitsWFS_reader
from pySurf.affine2D import plot_transform,find_rototrans
from pySurf.distanceTable import distanceTable
from pySurf.data2D_class import Data2D
from pySurf.data2D import resample_data
FEAf=r'G:\My Drive\Shared by Vincenzo\Metrology logs and data\Simulations\Coating_stress\VK20180619\coat_300_MPa_um_ur.fits' #300 MPa*um load
plt.figure(2)
plt.clf()
#manually adjust x and y scales to 4 in, adjsut units and signs.
fdata,xf,yf=fitsWFS_reader(FEAf) #can accept ypix, ytox,..
#xf,yf,fdata=yf,xf,fdata.T
fdata=fdata-correct_misalignment(fdata)[0]
fdata=-fdata*1000000. #m to um
#fitsWFS_reader makes a mysterious change of sign, that is good with WK's
#data that are bump negative conversion.
#scale and center axes (100 mm square image size)
nx=fdata.shape[0]
scale=101.6/nx
xf=(xf-span(xf).sum()/2)*scale
yf=(yf-span(yf).sum()/2)*scale
df=Data2D(fdata,xf,yf,units=['mm','mm','$\mu$m'],name='VK Simulation (cone)')
#rule is: corners have same sign as delta Radius
plt.clf()
df.plot()
display(plt.gcf())
df.save(fn_add_subfix(FEAf,'','.dat',strip=True,pre=outfolder+os.path.sep))
plt.savefig(fn_add_subfix(FEAf,'','.png',strip=True,pre=outfolder+os.path.sep))
diff=sdiff-df
plt.figure()
maximize()
ax1=plt.subplot(131)
sdiff.plot()
ax2=plt.subplot(132,sharex=ax1,sharey=ax1)
df.plot()
ax3=plt.subplot(133,sharex=ax1,sharey=ax1)
diff.plot()
display(plt.gcf())
plt.savefig(os.path.join(outfolder,prfolder,'starting_data.png'))
plt.close('all')
outfolder
The best fit for stress is determined by analytical formula for simple linear regression (intercept coefficient = 0). The fit is repeated for different azimuthal apertures. For each of them it is shown:
Each plot reports values for the ROI (small box) and for the entire surface (larger box) (the two are identical for the crop image at point 2)
Used functions (for who is interested in details).
print(help(trioptimize))
print('---------------------------')
print(help(scale_fit2))
print('---------------------------')
print(help(fom))
print('---------------------------')
print(help(fom_sl))
allres=pd.DataFrame()
os.makedirs(os.path.join(outfolder,prfolder),exist_ok=True)
plt.close('all')
#initialize allres
scales=trioptimize(sdiff,df,fom=fom,
rois=[[[-10,10],[-45,45]],[[-20,20],[-45,45]],[[-30,30],[-45,45]],
[[-37,37],[-45,45]],None],dis =True,
outfile=os.path.join(outfolder,prfolder,'VK_stress_fit'))
allres=allres.append(scales)
scales[['tbest','fom_roi','roi']].to_csv(os.path.join(outfolder,prfolder,'all_stats.txt'))
sel_ind=1 #index of ROI chosed for final results
tbest=scales.iloc[sel_ind]['tbest']
roi=scales.iloc[sel_ind]['roi']
print(tbest)
allres[['tbest','fom_roi','roi']]
plt.close('all')
comp2(p1-df*tbest,s1,roi=roi)
plt.suptitle('best factor = %.3f'%tbest)
display(plt.gcf())
plt.savefig(os.path.join(outfolder,prfolder,'best_fit.png'))
from pyProfile.profile import level_profile, subtract_profiles
from pySurf.points import extract_profile
## Extract axial profile
x1,y1 = level_profile(*(extract_profile((p1-df*tbest).topoints(),(0,-45),(0,45))))
x2,y2 = level_profile(*(extract_profile(s1.topoints(),(0,-45),(0,45))))
xd,yd = level_profile(*subtract_profiles(x2,y2,x1,y1))
plt.figure()
plt.plot(x1,y1,label='PZT data with applied correction')
plt.plot(x2,y2,label='Target Shape')
plt.plot(xd,yd,label='Residuals')
plt.xlabel(p1.units[0])
plt.ylabel(p1.units[2])
plt.grid(1)
plt.ylim([-0.8,0.8])
plt.legend(loc=0)
plt.title('Simulated correction')
display(plt.gcf())
plt.savefig(os.path.join(outfolder,prfolder,'data_central_profile.png'))
prfolder='fit_VM' #partial results folder
os.makedirs(os.path.join(outfolder,prfolder),exist_ok=True)
The exact same procedure is repeated on a different set of data by Vanessa Marquez, representing a uniform stress film on front of substrate (Case2), having an integrated stress of 150 MPa um. It is then expected to find values that are about double of previous ones, but with opposite sign, since here the film is applied to front surface.
from pySurf.instrumentReader import FEAreader
FEAf2=r'G:\My Drive\Shared by Vincenzo\Metrology logs and data\Simulations\CoatingStress_Analysis\220mm_CoatingStress\Primary\220mmROC_Case1_MirrorSurfaceOnly.csv'
plt.figure(2)
plt.clf()
#manually adjust x and y scales to 4 in, adjsut units and signs.
fdata,xf,yf=points_autoresample(FEAreader(FEAf2)) #can accept ypix, ytox,..
#xf,yf,fdata=yf,xf,fdata.T
fdata=fdata-correct_misalignment(fdata)[0]
fdata=fdata*1000. #m to um
#fitsWFS_reader makes a mysterious change of sign, that is good with WK's
#data that are bump negative conversion.
#scale and center axes (100 mm square image size)
scale=1.016
xf=(xf-span(xf).sum()/2)*scale
yf=(yf-span(yf).sum()/2)*scale
df=Data2D(fdata,xf,yf,units=['mm','mm','$\mu$m'],name=os.path.basename(FEAf2))
#rule is: corners have same sign as delta Radius
plt.clf()
df.plot()
display(plt.gcf())
df.save(fn_add_subfix(FEAf2,'','.dat',strip=True,pre=outfolder+os.path.sep))
plt.savefig(fn_add_subfix(FEAf2,'','.png',strip=True,pre=outfolder+os.path.sep))
os.makedirs(os.path.join(outfolder,prfolder),exist_ok=True)
plt.close('all')
#initialize allres
scales=trioptimize(sdiff,df,fom=fom,
rois=[[[-10,10],[-45,45]],[[-20,20],[-45,45]],[[-30,30],[-45,45]],
[[-37,37],[-45,45]],None],dis =True,
outfile=os.path.join(outfolder,prfolder,'VM_stress_fit'))
allres=allres.append(scales)
scales[['tbest','fom_roi','roi']].to_csv(os.path.join(outfolder,prfolder,'all_stats.txt'))
sel_ind=1 #index of ROI chosed for final results
tbest=scales.iloc[sel_ind]['tbest']
roi=scales.iloc[sel_ind]['roi']
print(tbest)
allres[['tbest','fom_roi','roi']]
plt.close('all')
comp2(p1-df*tbest,s1)
plt.suptitle('best factor = %.3f'%tbest)
display(plt.gcf())
plt.savefig(os.path.join(outfolder,prfolder,'best_fit.png'))
from pyProfile.profile import level_profile, subtract_profiles
from pySurf.points import extract_profile
## Extract axial profile
x1,y1 = level_profile(*(extract_profile((p1-df*tbest).topoints(),(0,-45),(0,45))))
x2,y2 = level_profile(*(extract_profile(s1.topoints(),(0,-45),(0,45))))
xd,yd = level_profile(*subtract_profiles(x2,y2,x1,y1))
plt.figure()
plt.plot(x1,y1,label='PZT data with applied correction')
plt.plot(x2,y2,label='Target Shape')
plt.plot(xd,yd,label='Residuals')
plt.xlabel(p1.units[0])
plt.ylabel(p1.units[2])
plt.grid(1)
plt.ylim([-0.8,0.8])
plt.legend(loc=0)
plt.title('Simulated correction')
display(plt.gcf())
plt.savefig(os.path.join(outfolder,prfolder,'bestfit_profile.png'))
prfolder='fit_VK_70mm' #partial results folder
os.makedirs(os.path.join(outfolder,prfolder),exist_ok=True)
The exact same procedure is repeated on a different set of data by Vanessa Marquez, representing a uniform stress film on front of substrate (Case2), having an integrated stress of 150 MPa um. It is then expected to find values that are about double of previous ones, but with opposite sign, since here the film is applied to front surface.
from pySurf.instrumentReader import FEAreader
FEAf=r'G:\My Drive\Shared by Vincenzo\Metrology logs and data\Simulations\Coating_stress\VK20180619\coat_300_MPa_um_ur.fits' #300 MPa*um load
plt.figure(2)
plt.clf()
#manually adjust x and y scales to 4 in, adjsut units and signs.
fdata,xf,yf=fitsWFS_reader(FEAf) #can accept ypix, ytox,..
#xf,yf,fdata=yf,xf,fdata.T
fdata=fdata-correct_misalignment(fdata)[0]
fdata=-fdata*1000000. #m to um
#fitsWFS_reader makes a mysterious change of sign, that is good with WK's
#data that are bump negative conversion.
#scale and center axes (100 mm square image size)
nx=fdata.shape[0]
scale=101.6/nx
xf=(xf-span(xf).sum()/2)*scale
yf=(yf-span(yf).sum()/2)*scale
df=Data2D(fdata,xf,yf,units=['mm','mm','$\mu$m'],name='VK Simulation (cone)')
#rule is: corners have same sign as delta Radius
plt.clf()
df.plot()
display(plt.gcf())
os.makedirs(os.path.join(outfolder,prfolder),exist_ok=True)
from scripts.stress_compensation import comp2, scale_fit2, trioptimize, fom_rms as fom, fom_sl
from pySurf.instrumentReader import fitsWFS_reader
plt.close('all')
#initialize allres
scales=trioptimize(sdiff,df,fom=fom,
rois=[[[-10,10],[-35,35]],[[-20,20],[-35,35]],[[-30,30],[-35,35]],
[[-37,37],[-35,35]],None],dis =True,
outfile=os.path.join(outfolder,prfolder,'VK_stress_fit_70mm'))
allres=allres.append(scales)
scales[['tbest','fom_roi','roi']].to_csv(os.path.join(outfolder,prfolder,'all_stats.txt'))
sel_ind=1 #index of ROI chosed for final results
tbest=scales.iloc[sel_ind]['tbest']
roi=scales.iloc[sel_ind]['roi']
print(tbest)
allres[['tbest','fom_roi','roi']]
plt.close('all')
comp2(p1-df*tbest,s1)
plt.suptitle('best factor = %.3f'%tbest)
display(plt.gcf())
plt.savefig(os.path.join(outfolder,prfolder,'best_fit.png'))
from pyProfile.profile import level_profile, subtract_profiles
from pySurf.points import extract_profile
## Extract axial profile
x1,y1 = level_profile(*(extract_profile((p1-df*tbest).topoints(),(0,-45),(0,45))))
#x1b,y1b = level_profile(*(extract_profile((p1-df*(-0.33)).topoints(),(0,-45),(0,45))))
x2,y2 = level_profile(*(extract_profile(s1.topoints(),(0,-45),(0,45))))
xd,yd = level_profile(*subtract_profiles(x2,y2,x1,y1))
plt.figure()
plt.plot(x1,y1,label='PZT data with applied correction')
#plt.plot(x1b,y1b,label='PZT data with center correction')
plt.plot(x2,y2,label='Target Shape')
plt.plot(xd,yd,label='Residuals')
plt.xlabel(p1.units[0])
plt.ylabel(p1.units[2])
plt.grid(1)
plt.ylim([-0.8,0.8])
plt.legend(loc=0)
plt.title('Simulated correction')
display(plt.gcf())
from pyProfile.profile import level_profile, subtract_profiles
from pySurf.points import extract_profile
## Extract axial profile
x1,y1 = level_profile(*(extract_profile((p1-df*tbest).topoints(),(0,-45),(0,45))))
x2,y2 = level_profile(*(extract_profile(s1.topoints(),(0,-45),(0,45))))
xd,yd = level_profile(*subtract_profiles(x2,y2,x1,y1))
plt.figure()
plt.plot(x1,y1,label='PZT data with applied correction')
plt.plot(x2,y2,label='Target Shape')
plt.plot(xd,yd,label='Residuals')
plt.xlabel(p1.units[0])
plt.ylabel(p1.units[2])
plt.grid(1)
plt.ylim([-0.8,0.8])
plt.legend(loc=0)
plt.title('Simulated correction')
display(plt.gcf())
plt.savefig(os.path.join(outfolder,prfolder,'bestfit_profile.png'))
prfolder='fit_VK_narrowstrip' #partial results folder
os.makedirs(os.path.join(outfolder,prfolder),exist_ok=True)
plt.close('all')
#initialize allres
scales=trioptimize(sdiff,df,fom=fom,
rois=[[[-2,2],[-35,35]]],dis =True,
outfile=os.path.join(outfolder,prfolder,'VK_stress_fit_narrowstrip'))
allres=allres.append(scales)
scales[['tbest','fom_roi','roi']].to_csv(os.path.join(outfolder,prfolder,'all_stats.txt'))
sel_ind=0 #index of ROI chosed for final results
tbest=scales.iloc[sel_ind]['tbest']
roi=scales.iloc[sel_ind]['roi']
print(tbest)
allres[['tbest','fom_roi','roi']]
plt.close('all')
comp2(p1-df*tbest,s1)
plt.suptitle('best factor = %.3f'%tbest)
display(plt.gcf())
plt.savefig(os.path.join(outfolder,prfolder,'best_fit.png'))
from pyProfile.profile import level_profile, subtract_profiles
from pySurf.points import extract_profile
## Extract axial profile
x1,y1 = level_profile(*(extract_profile((p1-df*tbest).topoints(),(0,-45),(0,45))))
#x1b,y1b = level_profile(*(extract_profile((p1-df*(-0.33)).topoints(),(0,-45),(0,45))))
x2,y2 = level_profile(*(extract_profile(s1.topoints(),(0,-45),(0,45))))
xd,yd = level_profile(*subtract_profiles(x2,y2,x1,y1))
plt.figure()
plt.plot(x1,y1,label='PZT data with applied correction')
#plt.plot(x1b,y1b,label='PZT data with center correction')
plt.plot(x2,y2,label='Target Shape')
plt.plot(xd,yd,label='Residuals')
plt.xlabel(p1.units[0])
plt.ylabel(p1.units[2])
plt.grid(1)
plt.ylim([-0.8,0.8])
plt.legend(loc=0)
plt.title('Simulated correction')
display(plt.gcf())
from pyProfile.profile import level_profile, subtract_profiles
from pySurf.points import extract_profile
## Extract axial profile
x1,y1 = level_profile(*(extract_profile((p1-df*tbest).topoints(),(0,-45),(0,45))))
x2,y2 = level_profile(*(extract_profile(s1.topoints(),(0,-45),(0,45))))
xd,yd = level_profile(*subtract_profiles(x2,y2,x1,y1))
plt.figure()
plt.plot(x1,y1,label='PZT data with applied correction')
plt.plot(x2,y2,label='Target Shape')
plt.plot(xd,yd,label='Residuals')
plt.xlabel(p1.units[0])
plt.ylabel(p1.units[2])
plt.grid(1)
plt.ylim([-0.8,0.8])
plt.legend(loc=0)
plt.title('Simulated correction')
display(plt.gcf())
plt.savefig(os.path.join(outfolder,prfolder,'bestfit_profile.png'))
allres[['tbest','fom_roi','roi']].to_csv(os.path.join(outfolder,'all_stats.txt'))
from notebooktoall.transform import transform_notebook
#transform_notebook(ipynb_file=os.path.join(outfolder,os.path.basename(outfolder)+".ipynb"),
# export_list=["html", "py"],file_name)